RenderChunk = class()

function RenderChunk:init(chunk,y0)
    self.chunk = chunk
    self.x0 = chunk.xPos
    self.y0 = y0 * 16
    self.z0 = chunk.zPos
    self.x1 = self.x0 + 16
    self.y1 = self.y0 + 16
    self.z1 = self.z0 + 16
    self.x = (self.x0 + self.x1) / 2
    self.y = (self.y0 + self.y1) / 2
    self.z = (self.z0 + self.z1) / 2
    self.aabb = AABB(self.x0,self.y0,self.z0,self.x1,self.y1,self.z1)
    self.binded = true
    self.ready = false
    self.dirty = true
    self.t = {Tesselator(),Tesselator()}
end

-- 解除绑定
function RenderChunk:unbind()
    self.ready = false
    self.binded = false
    self.chunk = nil
end

function RenderChunk:render(layer,eyePos)
    if self.binded and self.ready then
        self.t[layer].mesh.shader.EyePos = eyePos
        self.t[layer].mesh.shader.GlobalColor = world.globalColor
        self.t[layer].mesh.shader.FogColor = world.fogColor
        self.t[layer].mesh:draw()
    end
end

function RenderChunk:rebuild()
    if not self.chunk.readyToRender then
        return
    end
    self.rebuilding = true
    self.dirty = false
    chunkUpdated = chunkUpdated + 1
    local t,c,x0,y0,z0 = self.t,self.chunk,self.x0,self.y0,self.z0
    local bs = Block.blocks
    local id
    t[1]:begin()
    t[2]:begin()
    t[1]:bindTex(Tex)
    t[2]:bindTex(Tex)
    shader("Project:AlphaShader")
    t[1]:setShader(shader("Project:TerrainShader"))
    t[2]:setShader(shader("Project:AlphaShader"))
    for x = 0,15,15 do
        for y = 0,15 do
            for z = 0,15 do
                id = c:getBlock(x,y0 + y,z)
                if id ~= 0 then
                    bs[id]:render(t,x0 + x,y0 + y,z0 + z)
                end
            end
        end
    end
    if self:tryYield() then return end
    for y = 0,15,15 do
        for x = 1,14 do
            for z = 0,15 do
                id = c:getBlock(x,y0 + y,z)
                if id ~= 0 then
                    bs[id]:render(t,x0 + x,y0 + y,z0 + z)
                end
            end
        end
    end
    if self:tryYield() then return end
    for z = 0,15,15 do
        for x = 1,14 do
            for y = 1,14 do
                id = c:getBlock(x,y0 + y,z)
                if id ~= 0 then
                    bs[id]:render(t,x0 + x,y0 + y,z0 + z)
                end
            end
        end
    end
    if self:tryYield() then return end
    for x = 1,14 do
        for y = 1,14 do
            for z = 1,14 do
                id = c:getBlock(x,y0 + y,z)
                if id ~= 0 then
                    bs[id]:renderInChunk(t,x,y0 + y,z,c)
                end
            end
        end
        if x % 3 == 0 then
            if self:tryYield() then return end
        end
    end
    t[1]:End()
    t[2]:End()
    t[2].mesh.shader.MinAlpha = 0.1
    t[2].mesh.shader.RenderDistance = math.sqrt(worldRenderer.viewDistance)
    t[2].mesh.shader.FogControl = vec2(0.5,1.0)
    t[1].mesh.shader.RenderDistance = math.sqrt(worldRenderer.viewDistance)
    t[1].mesh.shader.FogControl = vec2(0.5,1.0)
    -- t[1].mesh.shader.GlobalColor = color(255, 255, 255, 255)
    -- t[2].mesh.shader.GlobalColor = color(255, 255, 255, 255)
    self.ready = true
    self.rebuilding = false
end

function RenderChunk:distanceToSqr(pos)
    local xa = pos.x - self.x
    local ya = pos.y - self.y
    local za = pos.z - self.z
    return xa * xa + ya * ya + za * za
end

function RenderChunk:tryYield()
    if GameState == Gaming then
        Thread.wait()
        if (not self.binded) or self.dirty then 
            self.rebuilding = false
            return true 
        end
    end
    return false
end
